﻿/*************************************************
  Copyright (C), 2014-2017, lmd Tech. Co., Ltd.
  文 件  名:	Src\CxExtension\.cs
  作       者:	陈佳
  版       本:	1.0
  完成日期:	2017//
  功能描述:	可以在调用自身提供的遍历函数中安全删除添加元素
  主要功能:
*************************************************/

using System;
using System.Collections;
using System.Collections.Generic;
using CxExtension;
using JetBrains.Annotations;

namespace CxExtension
{
	/// <summary>
	/// 可以在遍历中安全删除元素的集合模板
	/// </summary>
	/// <typeparam name="T">item type</typeparam>
	/// <typeparam name="CT">conllection type</typeparam>
	public abstract class CollectionDeleteSafeTemplate<CT,T>: ICollection<T> where CT :ICollection<T>, new()
	{
		protected readonly CT mCollection = new CT();
		private readonly Queue<T> mAddQue = new Queue<T>();
		private readonly Queue<T> mRemoveQue = new Queue<T>();
		private bool mIsForeach = false;

		#region Implementation of ICollection<T>


		public int Count
		{
			get { return CollectionCount_ + mAddQue.Count - mRemoveQue.Count; }
		}

		public bool IsReadOnly
		{
			get { return mCollection.IsReadOnly; }
		}

		/// <summary>
		/// 添加元素,可以在ForechAll函数遍历中使用
		/// </summary>
		/// <param name="it"></param>
		public void Add([NotNull] T it)
		{
			if (it == null) throw new ArgumentNullException("it");
			
			if(mIsForeach)
			{
				addAddQue(it);
			}
			else
			{
				add_(it);
			}
		}

		public void Clear()
		{
			clear_();
			mAddQue.Clear();
			mRemoveQue.Clear();
		}

		public bool Contains([NotNull] T it)
		{
			if (it == null) throw new ArgumentNullException("it");

			var contain = contains_(it) || mAddQue.Contains(it);
			return contain;
		}

		public virtual void CopyTo(T[] array, int arrayIndex)
		{
			mCollection.CopyTo(array,arrayIndex);
		}
		/// <summary>
		/// 移除某个元素,可以在调用ForechAll函数遍历中使用,
		/// </summary>
		/// <param name="it"></param>
		public bool Remove([NotNull] T it)
		{
			if (it == null) throw new ArgumentNullException("it");

			if (mIsForeach)
			{
				addRemoveQue(it);
			}
			else
			{
				return remove_(it);
			}

			return true;
		}


		#endregion
		/// <summary>
		/// 遍历所有元素,可以在遍历中安全的删除元素
		/// </summary>
		/// <param name="func"></param>
		public void ForeachAll([NotNull] Action<T> func)
		{
			if (func == null) throw new ArgumentNullException("func");
			Action<CT> foreachAction = it => foreach_(func);
			ForeachAll(foreachAction);
		}

		/// <summary>
		/// for each all item,delete item if func return true
		/// </summary>
		/// <param name="func"></param>
		public void ForeachAllSelectRemove([NotNull] Func<T,bool> func)
		{
			if (func == null) throw new ArgumentNullException("func");
			Action<CT> foreachAction = it =>
			{
				//foreach_(func, remove_v);
				foreach_(func, RemoveFc);
			};
			ForeachAll(foreachAction);

		}

		private void RemoveFc(T it)
		{
			Remove(it);
		}
		public void ForeachAll([NotNull] Action<CT> foreachAction)
		{
			if (foreachAction == null) throw new ArgumentNullException("foreachAction");
			var count = CollectionCount_;
			if (count > 0)
			{
				mIsForeach = true;
				foreachAction(mCollection);
				//foreach_(func);
				mIsForeach = false;
			}
			//移除遍历中要删除的元素,和添加遍历中要添加的元素
			mRemoveQue.DequeueAll((Action<T>)remove_v);
			mAddQue.DequeueAll((Action<T>)add_);
		}
		#region abstract



		#endregion
		#region virtual

		protected abstract void foreach_(Action<T> func);
		protected abstract void foreach_(Func<T,bool> func,Action<T> selectAction);
		protected virtual int CollectionCount_
		{
			get { return mCollection.Count; }
		}

		/// <summary>
		/// 直接添加某个元素
		/// //mConllect.Add(it);
		/// </summary>
		/// <param name="it"></param>
		protected virtual void add_(T it)
		{
			mCollection.Add(it);
		}

		protected virtual bool contains_(T it)
		{
			return mCollection.Contains(it);
		}

		protected virtual void clear_()
		{
			mCollection.Clear();
		}

		/// <summary>
		/// 直接移除某个元素
		/// mConllect.Remove(it);
		/// </summary>
		/// <param name="it"></param>
		protected virtual bool remove_(T it)
		{
			return mCollection.Remove(it);
		}
		#endregion
		#region private

		private void remove_v(T it)
		{
			remove_(it);
		}
		/// <summary>
		/// 添加到待添加队列
		/// </summary>
		/// <param name="it"></param>
		private void addAddQue(T it)
		{
			if(mAddQue.Contains(it))
			{
				return;
			}
			mAddQue.Enqueue(it);
		}

		/// <summary>
		/// 添加到移除队列
		/// </summary>
		/// <param name="it"></param>
		private void addRemoveQue(T it)
		{
			mRemoveQue.Enqueue(it);
		}

		#endregion
		#region Implementation of IEnumerable

		public IEnumerator<T> GetEnumerator()
		{
			throw new NotImplementedException();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}

		#endregion
	}
}